//
//  UIImage+Ext.swift
//  TTCOM-iOS
//
//  Created by Toj on 5/26/22.
//

import UIKit

public func UIImageContext(size: CGSize, _ completing: ((_ context: CGContext?)->Void)) -> UIImage? {
    
    // 开启个位图上下文
    UIGraphicsBeginImageContextWithOptions(size, false, 1)
    // 获取当前上下文
    let context = UIGraphicsGetCurrentContext()
    completing(context)
    // 获取上下文内容
    let image = UIGraphicsGetImageFromCurrentImageContext()
    // 退出上下文
    UIGraphicsEndImageContext()
    return image
}

public extension UIImage {
    
    convenience init?(resource named: String) {
        self.init(named: named, in: .main, compatibleWith: nil)
    }
}

public extension UIImage {
    
    /** 添加圆角, 边框为辅 */
    func st_setCorner(
        size: CGSize,
        radius: CGFloat,
        borderWidth: CGFloat = 0,
        borderColor: UIColor = .black
    ) -> UIImage? {
        let borderLine = borderWidth * 2
        let cornerRadius = radius - borderLine
        
        var rect = CGRect.zero
        rect.origin.x = borderLine * 0.5
        rect.origin.y = borderLine * 0.5
        rect.size.width = size.width - borderLine
        rect.size.height = size.height - borderLine
        
        let image = UIImageContext(size: size) { context in
            // 创建路径并绘制渐变
            let borderPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
            context?.addPath(borderPath.cgPath)
            guard borderLine > 0 else {
                draw(in: rect)
                return
            }
            // 绘制边框
            borderPath.lineWidth = borderLine
            borderColor.setStroke()
            borderPath.stroke()
            borderPath.addClip()
            draw(in: rect)
        }
        return image
    }
    
    /** 添加边框, 圆角为辅 */
    func st_setBorder(
        size: CGSize,
        borderWidth: CGFloat = 1,
        borderColor: UIColor = .black,
        radius: CGFloat = 0
    ) -> UIImage? {
        let borderLine = borderWidth * 2
        
        let cornerRadius = radius - borderLine * 0.5
        var rect = CGRect.zero
        rect.origin.x = borderWidth
        rect.origin.y = borderWidth
        rect.size.width  = size.width  - borderLine
        rect.size.height = size.height - borderLine
        
        let image = UIImageContext(size: size) { context in
            // 创建路径并绘制渐变
            let borderPath = UIBezierPath(roundedRect: rect, cornerRadius: radius)
            context?.addPath(borderPath.cgPath)
            // 绘制边框
            borderColor.setStroke()
            borderPath.lineWidth = borderLine
            borderPath.stroke()
            borderPath.addClip()
            draw(in: rect)
        }
        return image
    }
}

// MARK: - 生成特殊图片
public extension UIImage {
    
    /**
     * 生成一个虚线图片
     * size: 上下文图大小/ 图片大小, 一般View多大上下文就是多大
     * color: 虚线颜色
     * lineSize: 虚线宽度, 高度
     * space： 虚线之间间距, 默认与实线一样宽
     */
    static func st_dottedLine(
        size: CGSize,
        color: String,
        lineSize: CGSize,
        space: CGFloat = 0
    ) -> UIImage? {
        return st_dottedLine(size: size,
                             color: color.to_color.cgColor,
                             lineSize: lineSize,
                             space: space)
    }
    
    static func st_dottedLine(
        size: CGSize,
        color: UIColor,
        lineSize: CGSize,
        space: CGFloat = 0
    ) -> UIImage? {
        return st_dottedLine(size: size,
                             color: color.cgColor,
                             lineSize: lineSize,
                             space: space)
    }
    
    static func st_dottedLine(
        size: CGSize,
        color: CGColor,
        lineSize: CGSize,
        space: CGFloat = 0
    ) -> UIImage? {
        guard size != .zero else { return nil }
        
        let lWidth = lineSize.width
        let lHeight = lineSize.height
        let cHeight = size.height
        
        let lineWidth = lWidth >= 1 ? lWidth : 1
        let lineHeight = fmin(lHeight, cHeight)
        let lineSpace = space > 0 ? space : lineWidth
        let fixHeight = lineHeight <= 1 ? lineHeight : 0
        let lineStartY = (cHeight - fixHeight) * 0.5
        
        let image = UIImageContext(size: size) { context in
            /// 设置参数
            // 线条终点的形状
            context?.setLineCap(.butt)
            // 虚线颜色
            context?.setStrokeColor(color)
            // 虚线高度
            context?.setLineWidth(lineHeight)
            // phase: 起始位置
            // lengths:
            // 单: 虚线长度, 双: 间距长度. 只设置一个值虚线间距等长
            let lengths = [lineWidth, lineSpace]
            context?.setLineDash(phase: 0, lengths: lengths)
            
            /// 绘制
            // 设置虚线绘制起点
            let startPoint = CGPoint(x: 0, y: lineStartY)
            context?.move(to: startPoint)
            // 设置虚线绘制终点
            let endPoint = CGPoint(x: size.width, y: lineStartY)
            context?.addLine(to: endPoint)
            context?.strokePath()
        }
        return image
    }
    
    /** 单色图片 */
    static func st_image(
        color: String,
        size: CGSize,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        return st_image(color: color.to_color.cgColor,
                        size: size,
                        corner: radius,
                        borderColor: borderColor,
                        borderWidth: borderWidth)
    }
    
    static func st_image(
        color: UIColor,
        size: CGSize,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        return st_image(color: color.cgColor,
                        size: size,
                        corner: radius,
                        borderColor: borderColor,
                        borderWidth: borderWidth)
    }
    
    static func st_image(
        color: CGColor,
        size: CGSize,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        let rect = CGRect(origin: .zero, size: size)
        let layer = CALayer()
        layer.frame = rect
        layer.backgroundColor = color
        if radius > 0 { layer.cornerRadius = radius }
        
        if borderColor != nil {
            layer.borderWidth = borderWidth
            layer.borderColor = borderColor?.cgColor
        }
        
        let renderer = UIGraphicsImageRenderer(size: size)
        let image = renderer.image { context in
            layer.render(in: context.cgContext)
        }
        return image
    }
    
    /**
     单色图片
     - NOTE: 另一种方法
     */
    static func st_image2(
        color: String,
        size: CGSize,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        return st_image2(color: color.to_color.cgColor,
                         size: size,
                         corner: radius,
                         borderColor: borderColor,
                         borderWidth: borderWidth)
    }
    
    static func st_image2(
        color: UIColor,
        size: CGSize,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        return st_image2(color: color.cgColor,
                         size: size,
                         corner: radius,
                         borderColor: borderColor,
                         borderWidth: borderWidth)
    }
    
    static func st_image2(
        color: CGColor,
        size: CGSize,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        let rect = CGRect(origin: .zero, size: size)
        
        let image = UIImageContext(size: rect.size) { context in
            // 创建路径并绘制渐变
            let borderPath = UIBezierPath(roundedRect: rect, cornerRadius: radius)
            context?.addPath(borderPath.cgPath)
            context?.clip()
            
            context?.setFillColor(color)
            context?.fill([rect])
            
            // 绘制边框
            borderColor?.setStroke()
            borderPath.lineWidth = borderWidth * 2
            borderPath.stroke()
        }
        return image
    }
}

// MARK: - 离屏渲染处理
public extension UIImage {
    /**
     * l: left
     * r: right
     * t: top
     * b: bottom
     */
    enum GDDirection: Int {
        case vertical   // 垂直方向 |, 从正上到正下
        case horizontal // 水平方向 -, 从正左到正右
        case backslash  // 反斜方向 \, 从左上到右下
        case slash      // 正斜方向 /, 从左下到右上
        
        func toPoint(size: CGSize) -> (start: CGPoint, end: CGPoint) {
            let w = size.width
            let h = size.height
            
            switch self {
            case .vertical:   // 垂直方向 |, 从正上到正下
                let start = CGPoint(x: w * 0.5, y: 0)
                let end   = CGPoint(x: w * 0.5, y: h)
                return (start, end)
            case .horizontal: // 水平方向 -, 从正左到正右
                let start = CGPoint(x: 0, y: h * 0.5)
                let end   = CGPoint(x: w, y: h * 0.5)
                return (start, end)
            case .backslash:  // 反斜方向 \, 从左上到右下
                let start = CGPoint(x: 0, y: 0)
                let end   = CGPoint(x: w, y: h)
                return (start, end)
            case .slash:      // 正斜方向 /, 从左下到右上
                let start = CGPoint(x: 0, y: h)
                let end   = CGPoint(x: w, y: 0)
                return (start, end)
            }
        }
    }
    
    /** 渐变图片 + 圆角 + 边框 */
    static func gd_image(
        gradient colors: [String],
        size: CGSize,
        direction: GADirection = .horizontal,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        var array: [CGColor] = []
        colors.forEach { array.append($0.to_color.cgColor) }
        
        return gd_image(gradient: array,
                        size: size,
                        direction: direction,
                        corner: radius,
                        borderColor: borderColor,
                        borderWidth: borderWidth
        )
    }
    
    static func gd_image(
        gradient colors: [UIColor],
        size: CGSize,
        direction: GADirection = .horizontal,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        var array: [CGColor] = []
        colors.forEach { array.append($0.cgColor) }
        
        return gd_image(gradient: array,
                        size: size,
                        direction: direction,
                        corner: radius,
                        borderColor: borderColor,
                        borderWidth: borderWidth
        )
    }
    
    static func gd_image(
        gradient colors: [CGColor],
        size: CGSize,
        direction: GADirection = .horizontal,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        let rect = CGRect(origin: .zero, size: size)
        let array = colors
        let startPoint = direction.point.startPoint
        let endPoint = direction.point.endPoint
        
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = rect
        gradientLayer.colors = array
        gradientLayer.startPoint = startPoint
        gradientLayer.endPoint = endPoint
        if radius > 0 {
            gradientLayer.cornerRadius = radius
        }
        if borderColor != nil {
            gradientLayer.borderWidth = borderWidth
            gradientLayer.borderColor = borderColor?.cgColor
        }
        
        let renderer = UIGraphicsImageRenderer(size: size)
        let image = renderer.image { context in
            gradientLayer.render(in: context.cgContext)
        }
        
        return image
    }
    
    /**
     渐变图片 + 圆角 + 边框
     - NOTE: 另外一种方法
     */
    static func gd_image2(
        gradient colors: [String],
        size: CGSize,
        direction: GDDirection = .horizontal,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        var array: [CGColor] = []
        colors.forEach { array.append($0.to_color.cgColor) }
        
        return gd_image2(gradient: array,
                         size: size,
                         direction: direction,
                         corner: radius,
                         borderColor: borderColor,
                         borderWidth: borderWidth
        )
    }
    
    static func gd_image2(
        gradient colors: [UIColor],
        size: CGSize,
        direction: GDDirection = .horizontal,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        var array: [CGColor] = []
        colors.forEach { array.append($0.cgColor) }
        
        return gd_image2(gradient: array,
                         size: size,
                         direction: direction,
                         corner: radius,
                         borderColor: borderColor,
                         borderWidth: borderWidth
        )
    }
    
    static func gd_image2(
        gradient colors: [CGColor],
        size: CGSize,
        direction: GDDirection = .horizontal,
        corner radius: CGFloat = 0,
        borderColor: UIColor? = nil,
        borderWidth: CGFloat = 1
    ) -> UIImage? {
        let bwidth = borderColor == nil ? 0 : borderWidth
        
        let cornerRadius = radius - bwidth
        let rect = CGRect(origin: .zero, size: size)
        var roundedRect = CGRect.zero
        roundedRect.origin.x = bwidth * 0.5
        roundedRect.origin.y = bwidth * 0.5
        roundedRect.size.width = size.width - bwidth
        roundedRect.size.height = size.height - bwidth
        
        // 创建渐变
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        var colorLocations: [CGFloat] = [0.0, 1.0]
        let cgColors = colors as CFArray
        
        guard let gradient = CGGradient(colorsSpace: colorSpace, colors: cgColors, locations: &colorLocations) else { return nil }
        
        let points = direction.toPoint(size: size)
        let startPoint = points.start
        let endPoint = points.end
        
        let image = UIImageContext(size: rect.size) { context in
            // 创建路径并绘制渐变
            let borderPath = UIBezierPath(roundedRect: roundedRect, cornerRadius: cornerRadius)
            context?.addPath(borderPath.cgPath)
            context?.saveGState()
            context?.clip()
            context?.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: [.drawsBeforeStartLocation])
            context?.restoreGState()
            
            // 绘制边框
            if borderColor != nil {
                borderColor?.setStroke()
                borderPath.lineWidth = borderWidth
            }
            borderPath.stroke()
        }
        return image
    }
}
